﻿using System;
using System.Text;
using System.Net;
using System.Globalization;
using System.Security.Cryptography;
using System.Data;
using System.IO;
using System.Xml;
using System.Collections.Generic;

namespace HelperService
{
  public class QueueHelper : Object
  {
    
    //    public static string myURI = "http://127.0.0.1:10001/";
    //    private static string myAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
    //    private static string myAccountName = "devstoreaccount1"; // same for everyone

    public static string queueAccount = "http://remotify.queue.core.windows.net";
    public QueueHelper()
      : base()
    {
    }

    public QueueHelper(string queueName)
    {
      queueName = queueName.Trim();
    }

    public static string QueueAccount
    {
      get
      {
        return queueAccount;
      }
    }

    public static DataSet GetQueueList()
    {
      DataSet result = null;
      string tmpURI =  QueueAccount + "/?comp=list&maxresults=10";
      //string tmpURI = myURI + myAccountName + "firstqueue?comp=metadata";

      // create base request object and modify
      HttpWebRequest request = Util.GetBaseRequest(tmpURI, "GET"); // create queue

      // create the canonized string we're going to sign
      string StringToSign = Util.GetBaseCanonizedString(request);
      StringToSign += "?comp=list"; // required by the signature

      // sign request
      Util.SignRequest(request, StringToSign);

      // execute our request and process the response 
      // (taken almost verbatum from the sample project)
      try
      {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          if (response.StatusCode == HttpStatusCode.OK)
          {
            using (Stream stream = response.GetResponseStream())
            {
              result = new DataSet();
              result.ReadXml(stream);
              stream.Close();
            }
          }
          else
            result = null;
          response.Close();
        }
      }
      catch (WebException we)
      {
        Console.WriteLine(we.Message);
        result = null;
      }
      return result;
    }

    public static bool Create(string queueName)
    {
      bool result = false;
      QueueHelper queue = new QueueHelper(queueName); // create base object
      HttpWebRequest request = Util.GetBaseRequest(QueueAccount + "/" + queueName, "PUT"); // create queue
      string stringToSign = Util.GetBaseCanonizedString(request);
      Util.SignRequest(request, stringToSign);
      try
      {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          if (response.StatusCode == HttpStatusCode.Created)
          {
            // as an addition we could parse the result and retrieve
            // queue properties at this point
            result = true;
          }
          else if (response.StatusCode == HttpStatusCode.NoContent)
          {
            result = true;
          }
          else
          {
            result = false;
          }
          response.Close();
        }
      }
      catch (WebException we)
      {
        if (we.Response != null && ((HttpWebResponse)we.Response).StatusCode == HttpStatusCode.Conflict)
        {
          result = true;
        }
        else
        {
          result = false;
        }
      }

      // return the result
      return (result);
    }

    public static bool Put(string deviceID, string queueName, string message)
    {
      bool result = false;

      // transform message payload
      System.Text.UTF8Encoding enc = new UTF8Encoding(false);
      byte[] baMessage = enc.GetBytes("<QueueMessage><MessageText>" + "DeviceID: "+deviceID.Trim() + ";Message: " + message.Trim() + "</MessageText></QueueMessage>");

      // create base request object and modify
      HttpWebRequest request = Util.GetBaseRequest(QueueAccount + "/" + queueName + "/messages", "POST"); // create queue
      request.ContentLength = baMessage.Length;

      // create the canonized string we're going to sign
      string stringToSign = Util.GetBaseCanonizedString(request);

      // sign request
      Util.SignRequest(request, stringToSign);

      try
      {
        // send request
        using (Stream requestStream = request.GetRequestStream())
        {
          requestStream.Write(baMessage, 0, baMessage.Length);
          requestStream.Close();
          using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
          {
            result = (response.StatusCode == HttpStatusCode.Created);

            response.Close();
          }
        }
      }
      catch (WebException we)
      {
        result = false;
      }
      return result;
    }

    /*<?xml version="1.0" encoding="utf-8"?>
     *   <QueueMessagesList>
     *     <QueueMessage>
     *       <MessageId>7091f69c-9e71-4ba1-89a5-4ac7549b5c99</MessageId>
     *       <InsertionTime>Sat, 19 Mar 2011 05:53:05 GMT</InsertionTime>
     *       <ExpirationTime>Sat, 26 Mar 2011 05:53:05 GMT</ExpirationTime>
     *       <PopReceipt>AgAAAAEAAAApAAAADAULSdroywE=</PopReceipt>
     *       <TimeNextVisible>Tue, 22 Mar 2011 21:44:13 GMT</TimeNextVisible>
     *       <MessageText>hello world</MessageText>
     *     </QueueMessage>
     *   </QueueMessagesList> */
    private static string GetMessagesForDevice(string queueName, string deviceID, string xmlMessage)
    {
      string messageText = string.Empty;
      string command = string.Empty;
      string messageDeviceId = string.Empty;
      Dictionary<string, string> messageContents = new Dictionary<string, string>();
      try
      {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xmlMessage);
        if (doc.InnerText == "") return string.Empty;
        XmlNodeList nodes = doc.GetElementsByTagName("QueueMessage");
        foreach (XmlNode n in nodes)
        {
          foreach (XmlNode n2 in n.ChildNodes)
          {
            messageContents.Add(n2.Name, n2.InnerText);
          }
        }
        messageText = messageContents["MessageText"];
        try
        {
          messageDeviceId = messageText.Split(new char[] { ';' })[0].Split(new char[] { ':' })[1].Trim();

          if (messageDeviceId == "" || deviceID == "*" || deviceID == messageDeviceId)
          {

            command = messageText.Split(new char[] { ';' })[1].Split(new char[] { ':' })[1].Trim();
            Delete(queueName, messageContents["MessageId"], messageContents["PopReceipt"]);
          }
        }
        catch { Delete(queueName, messageContents["MessageId"], messageContents["PopReceipt"]); }
      }
      catch (Exception ex)
      {
        command = "Error: " + ex.Message;
      }
      //return command;
      return TranslateCommand(command);
    }

    private static string TranslateCommand(string sentCommand)
    {
      string actualCommand = string.Empty;
      TableHelper table = new TableHelper();
      List<CommTranslate> commands = table.GetCommands();
      foreach (CommTranslate command in commands)
      {
        if (sentCommand == command.TagOfCommand)
        {
          actualCommand = command.ActualComm;
        }
      }
      return actualCommand;
    }

    public static string Get(string deviceID, string queueName, bool delete, int numOfMessages = 32)
    {
      //DataSet result = null;
      string xmlMessage = string.Empty;
      string command = string.Empty;
      string tmpQueryParms = String.Empty;
      tmpQueryParms = "numofmessages=" + numOfMessages.ToString(CultureInfo.InvariantCulture);
      tmpQueryParms = "&visibilitytimeout=2";
      

      string tmpURI = QueueAccount + "/" + queueName + "/messages?" + tmpQueryParms;

      // create base request object and modify
      HttpWebRequest request = Util.GetBaseRequest(tmpURI, "GET"); // create queue

      // create the canonized string we're going to sign
      string StringToSign = Util.GetBaseCanonizedString(request);

      // sign request
      Util.SignRequest(request, StringToSign);

      try
      {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          if (response.StatusCode == HttpStatusCode.OK)
          {
            using (Stream stream = response.GetResponseStream())
            {
              StreamReader reader = new StreamReader(stream);
              xmlMessage = reader.ReadToEnd();
              command = GetMessagesForDevice(queueName, deviceID, xmlMessage);
            }
          }
          response.Close();
        }

      }
      catch (WebException we)
      {
        
      }

      return command;
    }

    public static bool Delete(string queueName, string messageID, string receipt)
    {
      bool result = false;

      string tmpQueryParms = String.Empty;
      tmpQueryParms = "?popreceipt=" + receipt.Trim();

      string tmpURI = QueueAccount + "/" + queueName + "/messages/" + messageID.Trim() + tmpQueryParms;

      // create base request object and modify
      HttpWebRequest request = Util.GetBaseRequest(tmpURI, "DELETE"); // create queue

      // create the canonized string we're going to sign
      string stringToSign = Util.GetBaseCanonizedString(request);

      // sign request
      Util.SignRequest(request, stringToSign);

      try
      {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          if (response.StatusCode == HttpStatusCode.NoContent)
            result = true; // successfully deleted
          else if (response.StatusCode == HttpStatusCode.NotFound)
            result = true; // message was already deleted
          else
            result = false; // no such message found or other error
        }

      }
      catch (WebException we)
      {
        result = false;
      }

      return result;
    }

    public static int GetQueueDepth(string queueName)
    {
      int result = -1;
      string tmpURI = QueueAccount + "/" + queueName + "?comp=metadata";

      // create base request object and modify
      HttpWebRequest request = Util.GetBaseRequest(tmpURI, "GET"); // create queue

      // create the canonized string we're going to sign
      string stringToSign = Util.GetBaseCanonizedString(request);
      stringToSign += "?comp=metadata"; // required by the signature

      // sign request
      Util.SignRequest(request, stringToSign);

      // execute our request and process the response 
      // (taken almost verbatum from the sample project)
      try
      {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          if (response.StatusCode == HttpStatusCode.OK)
          {
            result = Convert.ToInt32(response.Headers["x-ms-approximate-messages-count"], CultureInfo.InvariantCulture);
          }

          response.Close();
        }
      }
      catch (WebException we)
      {
        result = -1;
      }

      return result;
    }
  }
}


//if (peek)
//{
//  if (tmpQueryParms.Length > 0)
//    tmpQueryParms += "&";
//  tmpQueryParms += "peekonly=" + peek.ToString(CultureInfo.InvariantCulture);
//}